#include "ConnectionTreeModel.h"

namespace SQLDoc
{
	ConnectionTreeModel::ConnectionTreeModel(QObject *parent /*= 0*/) : QAbstractItemModel(parent) 
	{
		m_rootItem = 0;
		m_connectionIcon = new QIcon();
		m_connectionIcon->addPixmap(QPixmap(QString::fromUtf8(":/ico/connection_ico16.png")), QIcon::Normal, QIcon::Off);

		m_databaseIcon = new QIcon();
		m_databaseIcon->addPixmap(QPixmap(QString::fromUtf8(":/ico/database_ico16.png")));

		m_tableIcon = new QIcon();
		m_tableIcon->addPixmap(QPixmap(QString::fromUtf8(":/ico/table_ico16.png")));
	}

	ConnectionTreeModel::~ConnectionTreeModel()
	{
		if (m_rootItem)
		{
			delete m_rootItem;
			m_rootItem = 0;
		}		
		delete m_connectionIcon;
		delete m_databaseIcon;
	}

	void ConnectionTreeModel::setRootItem(DBObject *item)
	{
		delete m_rootItem;
		m_rootItem = item;
	}

	QVariant ConnectionTreeModel::data(const QModelIndex &index, int role) const
	{
		if (!index.isValid())
			return QVariant();

		DBObject *item = static_cast<DBObject*>(index.internalPointer());

		switch (role)
		{
		case Qt::DecorationRole:
			if (item->objectType() == DBObject::DBOTYPE_CONNECTION)
				return *m_connectionIcon;
			else if (item->objectType() == DBObject::DBOTYPE_DATABASE)
				return *m_databaseIcon;
			else if (item->objectType() == DBObject::DBOTYPE_TABLE)
				return *m_tableIcon;
			else
				return QVariant();

		case Qt::DisplayRole:
			return item->name();

		case Qt::CheckStateRole:
			return item->checked();

		case Qt::ToolTipRole:
			return item->comment();

		default:
			return QVariant();
		}	
	}

	QModelIndex ConnectionTreeModel::index(int row, int column, const QModelIndex &parent /*= QModelIndex()*/) const
	{
		if (!hasIndex(row, column, parent))
			return QModelIndex();

		DBObject *parentItem;

		if (!parent.isValid())
			parentItem = m_rootItem;
		else
			parentItem = static_cast<DBObject*>(parent.internalPointer());

		DBObject *childItem = parentItem->childItem(row);
		if (childItem)
			return createIndex(row, column, childItem);
		else
			return QModelIndex();
	}

	QModelIndex ConnectionTreeModel::parent(const QModelIndex &child) const
	{
		DBObject* itemNode = itemFromIndex(child);

		if (!itemNode)
			return QModelIndex();

		DBObject *parentItem = itemNode->parentItem();
		if (!parentItem)
			return QModelIndex();

		DBObject *grandparentItem = parentItem->parentItem();
		if (!grandparentItem)
			return QModelIndex();

		int row = grandparentItem->childItems().indexOf(parentItem);
		return createIndex(row, child.column(), parentItem);
	}

	int ConnectionTreeModel::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const
	{
		DBObject *parentItem = itemFromIndex(parent);
		if (!parentItem)
			return 0;
		return parentItem->childCount();
	}

	int ConnectionTreeModel::columnCount(const QModelIndex &parent /*= QModelIndex()*/) const
	{
		return 1;
	}

	bool ConnectionTreeModel::hasChildren(const QModelIndex &parent /*= QModelIndex()*/) const
	{
		DBObject* item = itemFromIndex(parent);

		if (item)
		{
			if (item->objectType() == DBObject::DBOTYPE_CONNECTION)
			{
				// TODO : add check if any database is accessible with connection
				DBConnection* connection = reinterpret_cast<DBConnection*>(item);
				if (connection->databaseCount() > 0)
					return true;
			}
			else if (item->objectType() == DBObject::DBOTYPE_DATABASE)
			{
				// TODO : check if any tables exists
				DBDatabase* database = reinterpret_cast<DBDatabase*>(item);
				if (database->tablesCount() > 0)
					return true;
			}
			else if (item->objectType() == DBObject::DBOTYPE_ROOT)
			{
				return true;
			}
		}

		return false;
	}

	QVariant ConnectionTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
	{
		if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
			return "Connections";

		return QVariant();
	}

	bool ConnectionTreeModel::canFetchMore(const QModelIndex& parent) const
	{
		DBObject* item = itemFromIndex(parent);

		if (item && item->childCount() <= 0)
			return true;

		return false;
	}

	void ConnectionTreeModel::fetchMore(const QModelIndex& parent)
	{
		int rowsCount = 0;
		DBObject* item = itemFromIndex(parent);

		if (item)
		{
			if (item->objectType() == DBObject::DBOTYPE_CONNECTION)
			{
				DBConnection* connection = reinterpret_cast<DBConnection*>(item);

				// TODO : Find out how many databases exists
				rowsCount = connection->selectDatabases();

				beginInsertRows(parent, item->childCount(), item->childCount() + rowsCount - 1);

				// TODO : Get databases
				connection->rewriteDatabases();

				endInsertRows();
			}
			else if (item->objectType() == DBObject::DBOTYPE_DATABASE)
			{
				DBDatabase* db = reinterpret_cast<DBDatabase*>(item);

				// TODO : Find out how many tables exists
				rowsCount = db->selectTables();

				beginInsertRows(parent, item->childCount(), item->childCount() + rowsCount - 1);

				// TODO : Get tables
				db->rewriteTables();

				endInsertRows();
			}
		}
	}

	Qt::ItemFlags ConnectionTreeModel::flags(const QModelIndex &index) const
	{
		return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
	}

	bool ConnectionTreeModel::setData(const QModelIndex &index, const QVariant &value, int role /*= Qt::EditRole*/)
	{
		if (role == Qt::CheckStateRole)
		{
			Qt::CheckState state = (Qt::CheckState)value.toInt();
			DBObject *object = itemFromIndex(index);

			object->setChecked(state);
			if (object->parentItem())
				object->parentItem()->verifyCheckedState(state);

			// TODO : Check performance
			QAbstractItemModel::dataChanged(QModelIndex(), index);

			return true;
		}
		return QAbstractItemModel::setData(index, value, role);
	}

	DBObject *ConnectionTreeModel::itemFromIndex(const QModelIndex &itemIndex) const
	{
		if (itemIndex.isValid())
		{
			DBObject* itemNode = static_cast<DBObject*>(itemIndex.internalPointer());
			if (itemNode) return itemNode;
		}
		return m_rootItem;
	}

	void ConnectionTreeModel::addConnection(DBConnection* connection)
	{
		m_rootItem->addChild(connection);
		reset();
	}
}
